import { App, Controller, Get, Config, Inject, Provide, Param, Query } from '@midwayjs/decorator'
import { Application, Context } from 'egg'
import { gql } from 'graphql-request'
import { HttpService } from '@midwayjs/axios'

import { BaseController } from './base'
import { CODE } from '../constants/code'

const parser = require('xml2json')

function getFileType(ext) {
  if ([
    '.doc', '.docx', '.docm', '.dot', '.dotx', '.dotm',
    '.odt', '.fodt', '.ott', '.rtf', '.txt', '.html',
    '.htm', '.mht', '.xml', '.pdf', '.djvu', '.fb2',
    '.epub', '.xps'
  ].indexOf(ext) > -1) return 'word'

  if ([
    '.xls', '.xlsx', '.xlsm', '.xlt', '.xltx', '.xltm',
    '.ods', '.fods', '.ots', '.csv'
  ].indexOf(ext) > -1) return 'cell'

  if ([
    '.pps', '.ppsx', '.ppsm', '.ppt', '.pptx', '.pptm',
    '.pot', '.potx', '.potm', '.odp', '.fodp', '.otp'
  ].indexOf(ext) > -1) return 'slide'

  return 'word'
}

@Provide()
@Controller('/api/viewer')
export class OfficeViewerController extends BaseController {

  @App()
  app: Application

  @Inject()
  ctx: Context

  @Inject()
  httpService: HttpService

  @Config('office')
  officeConfig: any

  @Get('/:id')
  async viewer(@Param() id: number) {
    const {
      ie_attachment_by_pk
    } = await this.app.gqlRequest(gql`
      query ($id: Int!) {
        ie_attachment_by_pk (id: $id) {
          filename
          ext
          filepath
        }
      }
    `, { id })

    const {
      filename,
      ext,
      filepath
    } = ie_attachment_by_pk || {}

    if (!filename) {
      return this.notOk(CODE.NOT_FOUND)
    }

    await this.render(filename, ext, filepath)
  }

  @Get('/pdf/:id')
  async getPdf(@Param() id: number) {
    const {
      ie_attachment_by_pk
    } = await this.app.gqlRequest(gql`
      query ($id: Int!) {
        ie_attachment_by_pk (id: $id) {
          filename
          ext
          filepath
        }
      }
    `, { id })

    const {
      filename,
      ext,
      filepath
    } = ie_attachment_by_pk || {}

    if (!filename) {
      return this.notOk(CODE.NOT_FOUND)
    }

    const xml = await this.httpService.post(
      `${this.officeConfig.host}/ConvertService.ashx`
    , {
      async: false,
      filetype: ext.slice(1),
      outputtype: 'pdf',
      title: filename,
      url: filepath
    })

    return parser.toJson(xml)
  }

  @Get('/')
  async viewerByPath(@Query() filepath: string) {
    if (!filepath) {
      return this.notOk(CODE.NOT_FOUND)
    }

    const { ie_attachment } = await this.app.gqlRequest(gql`
      query ($filepath: String!) {
        ie_attachment (where: { filepath: { _eq: $filepath } }) {
          filename
          ext
        }
      }
    `, { filepath })

    if (ie_attachment.length === 0) {
      return this.notOk(CODE.NOT_FOUND)
    }

    const [{
      filename,
      ext
    }] = ie_attachment

    await this.render(filename, ext, filepath)
  }

  async render(filename, ext, filepath) {
    const data = {
      apiUrl: '/web-apps/apps/api/documents/api.js',
      file: {
        name: filename,
        ext: ext.substring(1),
        uri: this.officeConfig.fileHost + filepath, // TODO
        favorite: 'null'
      },
      editor: {
        type: 'embedded',
        documentType: getFileType(ext),
        isEdit: true,
        comment: false,
        fillForms: false,
        modifyFilter: true,
        modifyContentControl: true,
        review: false,
        reviewGroups: 'null',
        mode: 'edit',
        canBackToFolder: false,
        lang: 'zh',
        actionData: 'null',
        submitForm: false,
        plugins: 'null'
      }
    }

    await this.ctx.render('viewer.ejs', data)
  }
}